package com.ruoyi.util;
import java.util.concurrent.TimeUnit;

public class SnowflakeIdGenerator {
    private static final long EPOCH = 1672502400000L;

    // 机器ID所占位数
    private static final long WORKER_ID_BITS = 5L;
    // 数据中心ID所占位数
    private static final long DATACENTER_ID_BITS = 5L;
    // 序列号所占位数
    private static final long SEQUENCE_BITS = 12L;

    // 最大机器ID (31)
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    // 最大数据中心ID (31)
    private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);

    // 时间戳向左移位数(22)
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
    // 数据中心ID向左移位数(17)
    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
    // 机器ID向左移位数(12)
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;

    // 序列号掩码(4095)
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

    private final long workerId;      // 机器ID
    private final long datacenterId;  // 数据中心ID
    private long sequence = 0L;      // 序列号
    private long lastTimestamp = -1L; // 上次生成ID的时间戳

    /**
     * 构造函数
     * @param workerId 机器ID (0-31)
     * @param datacenterId 数据中心ID (0-31)
     */
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException("Worker ID 必须在 0 和 " + MAX_WORKER_ID + " 之间");
        }
        if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID 必须在 0 和 " + MAX_DATACENTER_ID + " 之间");
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    /**
     * 生成下一个ID
     * @return 雪花ID
     */
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        // 如果当前时间小于上次ID生成的时间戳，说明系统时钟回退过
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("时钟回退。拒绝生成 %d 毫秒的 ID", lastTimestamp - timestamp));
        }

        // 如果是同一毫秒生成的
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            // 同一毫秒的序列号用完
            if (sequence == 0) {
                // 等待到下一毫秒
                timestamp = waitNextMillis(lastTimestamp);
            }
        } else {
            // 新的一毫秒，序列号重置
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        // 组合各部分生成ID
        return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)
                | (datacenterId << DATACENTER_ID_SHIFT)
                | (workerId << WORKER_ID_SHIFT)
                | sequence;
    }

    /**
     * 等待到下一毫秒
     * @param lastTimestamp 上次生成ID的时间截
     * @return 当前时间戳
     */
    private long waitNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            try {
                TimeUnit.MICROSECONDS.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    public static void main(String[] args) {
        // 示例：创建ID生成器（数据中心ID=1，机器ID=1）
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);

        // 生成10个ID
        for (int i = 0; i < 10; i++) {
            long id = idGenerator.nextId();
            System.out.println("生成的雪花ID: " + id);
            System.out.println("二进制: " + Long.toBinaryString(id));
        }
    }
}
